package com.cloud.rpc.filter;

import com.alibaba.fastjson.JSON;
import com.cloud.common.domain.CloudApplicationContext;
import com.cloud.common.domain.CloudContext;
import com.cloud.rpc.constants.RpcConStants;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.rpc.*;

import java.util.Objects;

import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;

/**
 * rpc穿透 -> 提供者拦截器
 *
 * @author wangjian
 * @version 0.1.0
 * @create 2021年03月18日上午9:47
 * @since JDK 1.8
 * Life is so short,do something to make yourself happy,such as coding
 */
@Activate(group = PROVIDER, order = -200)
public class RpcProviderFilter implements Filter, Filter.Listener {

    private static final Logger logger = LoggerFactory.getLogger(RpcProviderFilter.class);

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        RpcContext context = RpcContext.getContext();
        // 获取最后一次调用的提供方IP地址
        String remoteHost = context.getRemoteHost();
        // 本端是否为提供端
        boolean isProviderSide = context.isProviderSide();
        if (isProviderSide) {
            logger.info("As provider, remoteHost :{" + remoteHost + "}, methodName:{" + context.getMethodName() + "}");
            providerSide();
        }
        //实际的rpc调用
        return invoker.invoke(invocation);
    }

    /**
     * 提供者获取RPC上下文至本地上下文
     */
    private void providerSide() {
        CloudContext cloudContext = CloudApplicationContext.getInstance().getContext();
        if (Objects.isNull(cloudContext.getAccId())) {
            //如果本地上下文空，说明是通过rpc方式到达
            String rpcContext = RpcContext.getContext().getAttachment(RpcConStants.CLOUD_CONTEXT_MARK);
            if (StringUtils.isEmpty(rpcContext)) {
                logger.error("As provider，RpcContext.cloudContext There was no transmission !!!");
                return;
            }
            cloudContext = JSON.parseObject(rpcContext, CloudContext.class);
            assert cloudContext != null;
            CloudApplicationContext.getInstance().setContext(cloudContext);
        }
    }

    @Override
    public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
        // 服务提供者，在完成服务调用后，应当及时回收上下文信息¬
        CloudApplicationContext.getInstance().removeContext();
    }

    @Override
    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
        logger.error("RpcProviderFilter传递时出现异常！", t);
        CloudApplicationContext.getInstance().removeContext();
    }
}
